#include "cc__gen.hpp"

int main() {
    langcc::global_init();
    bool ok = true;
    auto L = lang::cc::init();
    ok = ok && L->test_example(langcc::Some<std::string>("Expr"), "x().y", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Expr"), "x.y()", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Expr"), "x.A::b", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Expr"), "A::x.b", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "struct A {\n    int x;\n    float y;\n};\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "struct A {\n    void foo() {\n        p = 3;\n    }\n};\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "struct A {\n    void foo() {\n        p = 3;\n    }\n    void bar() {\n        q = 4;\n    }\n};\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "namespace NS {\n    void foo() {\n        p = 3;\n    }\n\n    void bar() {\n        q = 4;\n    }\n\n    struct baz {\n        void qux() {\n        }\n        void quux() {\n        }\n    };\n}\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Stmt"), "{\n    {\n        {\n            {\n                {\n                    x + 3;\n                }\n            }\n        }\n    }\n}", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "inline void pr(ostream& os, const Buffer& A) {\n    fmt(os, \"Buffer[{}]:\\n\", A.N_);\n    if (A.N_ <= 256L + 64L) {\n        for (Int i = 0; i _LT_ A.N_; i++) {\n            os << byte_to_hex(A.v_[i]);\n            pr_buffer_sep(os, i);\n        }\n        if (A.N_ % 64 != 0) {\n            os << \"\\n\";\n        }\n    } else {\n        for (Int i = 0; i _LT_ 256L; i++) {\n            os << byte_to_hex(A.v_[i]);\n            pr_buffer_sep(os, i);\n        }\n        os << \"...\\n\";\n        Int N_base = A.N_ - 64;\n        for (Int i = 0; i _LT_ 64; i++) {\n            os << byte_to_hex(A.v_[N_base + i]);\n            pr_buffer_sep(os, i);\n        }\n    }\n}\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "template<typename T> inline void fmt_acc(ostream& os, vector<string>& args_acc, T t) {\n    args_acc.push_back(pr_str(t));\n}\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "namespace BinOp {\n    enum struct Which {\n        ADD,\n        SUB,\n        MUL,\n        DIV,\n    };\n\n    struct _S: Expr::_S {\n        Which which_binop_;\n        Expr_S lhs;\n        Expr_S rhs;\n        _S(Which w, Expr_S lhs, Expr_S rhs) : which_binop_(w), Expr::_S(Expr::Which::BinOp), lhs(lhs), rhs(rhs) {\n        }\n    };\n\n    Expr::BinOp_S make_ADD(Expr_S lhs, Expr_S rhs) {\n        return make_shared<Expr::BinOp::_S>(Which::ADD, lhs, rhs);\n    }\n}\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Module"), "namespace Expr {\n    enum struct Which {\n        _UNINIT_,\n        BinOp,\n        Lit,\n    };\n}\n\nnamespace Expr {\n    struct _S: std::enable_shared_from_this<_S> {\n        Expr::Which which_expr_;\n        _S(Expr::Which w) : which_expr_(w) {\n        }\n        _S() = delete;\n        virtual ~_S() {\n        }\n        Expr::Which which() {\n            return which_expr_;\n        }\n        bool is_BinOp() {\n            return which_expr_ == Expr::Which::BinOp;\n        }\n        bool is_Lit() {\n            return which_expr_ == Expr::Which::Lit;\n        }\n        Expr::BinOp_S as_BinOp() {\n            AT(this->is_BinOp());\n            return dynamic_pointer_cast<Expr::BinOp::_S>(this->shared_from_this());\n        }\n        Expr::Lit_S as_Lit() {\n            AT(this->is_Lit());\n            return dynamic_pointer_cast<Expr::Lit::_S>(this->shared_from_this());\n        }\n    };\n}\n\nnamespace Expr::BinOp {\n    enum struct Which {\n        _UNINIT_,\n        Add,\n        Sub,\n        Mul,\n        Div,\n    };\n}\n\nnamespace Expr {\n    Expr::BinOp_S make_BinOp(Expr::BinOp::Which w, Expr_S lhs, Expr_S rhs) {\n        return make_shared<Expr::BinOp::_S>(w, lhs, rhs);\n    }\n}\n\nvoid pr(ostream& os, FmtFlags flags, Expr::BinOp::Op op) {\n    switch (op) {\n        case Expr::BinOp::Op::Add: {\n            os << \"+\";\n            break;\n        }\n        case Expr::BinOp::Op::Sub: {\n            os << \"-\";\n            break;\n        }\n        case Expr::BinOp::Op::Mul: {\n            os << \"*\";\n            break;\n        }\n        case Expr::BinOp::Op::Div: {\n            os << \"/\";\n            break;\n        }\n        default: {\n            AX();\n        }\n    }\n}\n", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Expr"), "x().y().z(a, b, c)", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Stmt"), "for (Int i = 0; i _LT_ n; i++) {\n    y[i] = x[i];\n}", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Expr"), "x->m_->at(i)->length()", -1, true);
    ok = ok && L->test_example(langcc::Some<std::string>("Stmt"), "for (i1 = 0; i1 _LT_ x->m_->at(i)->length(); i1++) {\n    expr_data::Node::Expr_T y = xform(x->m_->at(i)->at(i1), f);\n    ret1->push_back(y);\n}", -1, true);
    return !ok;
}
